package utils

import (
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	commonmodel "helloword01/31chatroom/common/model"
	"log"
	"net"
	"regexp"
	"strconv"
)

type Transfer struct {
	Conn net.Conn
	Buf  [8096]byte
}

// ReadPkg
//
//	@Description: 从conn读取数据，反序列化成 -> message.Message
//	@receiver this
//	@return mes
//	@return err
func (this *Transfer) ReadPkg() (mes commonmodel.Message, err error) {
	//conn.Read 在conn没有被关闭的情况下，才会阻塞 ，如果客户端关闭了 conn 则，就不会阻塞

	//读取前4个字节
	_, err = this.Conn.Read(this.Buf[:4])
	if err != nil {
		return
	}
	//将前4个字节转成一个 uint32类型,即为消息的长度
	var dataLen = binary.BigEndian.Uint32(this.Buf[0:4])

	//再读取dataLen长度的数据，即消息内容
	n, err := this.Conn.Read(this.Buf[:dataLen])
	if n != int(dataLen) || err != nil {
		return
	}
	log.Println("[读取长度]:", dataLen)

	//反序列化成 -> message.Message
	err = json.Unmarshal(this.Buf[:dataLen], &mes)
	if err != nil {
		return
	}
	log.Println("[读取消息]:", mes)
	return
}

// WritePkg
//
//	@Description:写消息到conn
//	@param conn
//	@param data[]byte
//	@return err
func WritePkg(conn net.Conn, data []byte) (err error) {
	//1.发送包的长度~
	//1.1	计算消息的长度
	var dataLen = uint32(len(data))
	//1.2	定义一个长度为4的byte数组
	var bytes [4]byte
	//1.3	将消息长度放入切片buf[:4]	binary包实现了简单的数字与字节序列的转换以及变长值的编解码
	//tips:
	//定义一个数组，然后通过引用去操作 [一种切片的定义方式]
	//var arr [5]int = [...]int{2, 4, 6, 7, 8}
	//从index=0 开始，到index=2结束，不包含index=2
	//var s1 = arr[0:2]
	binary.BigEndian.PutUint32(bytes[:4], dataLen)
	//1.4	发送长度
	log.Println("[发出长度]:", dataLen)
	n, err := conn.Write(bytes[:4])
	if n != 4 || err != nil {
		return errors.New("[发送]消息数长度错误~")
	}
	//2.发送消息本身
	log.Println("[发出消息]:", string(data))
	n, err = conn.Write(data)
	if n != int(dataLen) || err != nil {
		return errors.New("[发送]消息数错误~")
	}
	return nil
}

func (this *Transfer) WritePkg(data []byte) (err error) {
	//消息长度
	var dataLen = uint32(len(data))
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[:4], dataLen)
	//发送长度
	log.Println("[发出长度]:", dataLen)
	n, err := this.Conn.Write(buf[:4])
	if n != 4 || err != nil {
		return errors.New("[发送]消息数长度错误~")
	}
	//发送消息本身
	log.Println("[发出消息]:", string(data))
	n, err = this.Conn.Write(data)
	if n != int(dataLen) || err != nil {
		return errors.New("[发送]消息数错误~")
	}
	return nil
}

// BuildMessage
//
//	@Description: 构建通用消息体
//	@param data
//	@param msgType
//	@return res
//	@return err
func BuildMessage(data []byte, msgType string) (res []byte, err error) {
	var mes commonmodel.Message
	mes.Type = msgType
	mes.Data = string(data)
	//序列化
	data, err = json.Marshal(mes)
	if err != nil {
		return nil, errors.New(commonmodel.SerializeJsonError)
	}
	return data, nil

}

// ParsePrivateMes
//
//	@Description:
//	@param input
//	@return int
//	@return string
//	@return error
func ParsePrivateMes(input string) (int, string, error) {
	// 定义正则表达式模式
	re := regexp.MustCompile(`\[(\d+)\](.*)`)
	matches := re.FindStringSubmatch(input)

	if len(matches) != 3 {
		return 0, "", fmt.Errorf("输入格式不正确")
	}

	// 解析 id
	id, err := strconv.Atoi(matches[1])
	if err != nil {
		return 0, "", err
	}

	// 获取内容
	content := matches[2]

	return id, content, nil
}
